/**
 * Copyright (c) 2016 Lenovo Group
 * All Rights Reserved.
 * 
 * Project Name:app-gateway
 * Create Time: 2016年1月18日 下午5:25:10
 */
package com.lenovo.lmrp.server.appgateway.spi;

import java.util.Base64;
import java.util.Calendar;
import java.util.Map;
import java.util.Objects;

import javax.ws.rs.Consumes;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.lenovo.lmrp.api.appgateway.IAppSoftware;
import com.lenovo.lmrp.api.itsmgateway.IItsmEngineer;
import com.lenovo.lmrp.api.model.RestResponse;
import com.lenovo.lmrp.api.model.view.AppVO;
import com.lenovo.lmrp.api.model.view.FeedbackVO;
import com.lenovo.lmrp.api.model.view.LoginData;
import com.lenovo.lmrp.api.model.view.TokenVO;
import com.lenovo.lmrp.base.mq.MQAppGatewayEvent;
import com.lenovo.lmrp.base.mq.MQContent;
import com.lenovo.lmrp.base.mq.MQTopic;
import com.lenovo.lmrp.server.appgateway.AppSession;
import com.lenovo.lmrp.server.appgateway.RestClientFactory;
import com.lenovo.lmrp.server.appgateway.util.AppCache;
import com.lenovo.lmrp.server.appgateway.util.AppMQClient;
import com.lenovo.lmrp.server.appgateway.util.PropertiesUtil;
import com.lenovo.lmrp.server.appgateway.util.TokenGenerator;
import com.lenovo.sdc.framework.annotation.RestService;
import com.lenovo.sdc.framework.cache.ACacheClient;
import com.lenovo.sdc.framework.cache.CacheItem;
import com.lenovo.sdc.framework.mq.AMQClient;
import com.lenovo.sdc.framework.rest.RestClientProxy;
import com.lenovo.sdc.framework.util.CommonUtil;
import com.lenovo.sdc.framework.util.JSONHelper;

/**
 * @author zhangzhenga
 *
 */
@RestService
@Path("/app/v1")
@Produces("application/json;charset-utf-8")
@Consumes("application/json;charset-utf-8")
public class AppSoftwareImpl implements IAppSoftware {

    private static final Logger log = LoggerFactory.getLogger(AppSoftwareImpl.class);

    private String accesstoken;

    @HeaderParam("Authorization")
    private void setToken(String authorization) {
        if (!CommonUtil.isNullOrEmpty(authorization))
            this.accesstoken = authorization.substring(6);
    }

    /* (non-Javadoc)
     * @see com.lenovo.lmrp.api.appgateway.IAppSoftware#login(java.lang.String, com.lenovo.lmrp.api.model.view.LoginData)
     */
    public RestResponse<TokenVO> login(String itsmcode, LoginData loginData) {
        if (Objects.isNull(loginData)) {
            return new RestResponse<TokenVO>(1, "missing login data.", null);
        }
        if (CommonUtil.isNullOrEmpty(loginData.getLoginname())) {
            return new RestResponse<TokenVO>(1, "missing loginname.", null);
        }
        if (CommonUtil.isNullOrEmpty(loginData.getPassword())) {
            return new RestResponse<TokenVO>(1, "missing password.", null);
        }
        if (CommonUtil.isNullOrEmpty(loginData.getDeviceid())) {
            return new RestResponse<TokenVO>(1, "missing deviceid.", null);
        }
        if (CommonUtil.isNullOrEmpty(loginData.getCid())) {
            return new RestResponse<TokenVO>(1, "missing cid.", null);
        }
        String clearPwd;
        //解码登录密码，提交到ITSM认证
        try {
            String pwd = loginData.getPassword();
            byte[] pwdBytes = Base64.getDecoder().decode(pwd);
            byte[] pwdBytes2 = Base64.getDecoder().decode(pwdBytes);
            clearPwd = new String(pwdBytes2);
        }
        catch (Exception e) {
            log.error("error when decrypt pwd", e);
            return new RestResponse<TokenVO>(1, "error encrypt pwd.", null);
        }
        loginData.setPassword(clearPwd);
        //调用ITSM工程师认证接口
        RestClientProxy itsmProxy = RestClientFactory.getItsmGatewayClient();
        IItsmEngineer engineer = itsmProxy.getService(IItsmEngineer.class);

        RestResponse<Integer> itsmResponse = engineer.authenticate(itsmcode, loginData);
        if (itsmResponse.getEcode() == 0) {//ITSM 认证成功
            logoutRepeat(itsmcode, loginData);//处理重复登录
            TokenVO token = this.createToken(itsmcode, loginData);
            //发送MQ消息，通知Trace保存用户登录状态
            sendMQ(MQAppGatewayEvent.LOGIN, loginData, itsmcode);
            return new RestResponse<TokenVO>(0, "OK", token);
        }
        else {
            return new RestResponse<TokenVO>(itsmResponse.getEcode(), itsmResponse.getReason(), null);
        }

    }

    /* (non-Javadoc)
     * @see com.lenovo.lmrp.api.appgateway.IAppSoftware#logout(java.lang.String)
     */
    public RestResponse<Integer> logout(String itsmcode) {
        try {
            CacheItem<AppSession> cacheSession = AppCache.getClient().get(AppSession.class,accesstoken);
            if (!Objects.isNull(cacheSession) && !Objects.isNull(cacheSession.getValue())) {
                AppSession session = cacheSession.getValue();
                //发送MQ消息，通知Trace注销用户
                sendMQ(MQAppGatewayEvent.LOGOUT, session.getLoginData(), itsmcode);
                AppCache.getClient().remove(accesstoken);
                AppCache.getClient().remove(session.getRefreshToken());
                AppCache.getClient().remove(itsmcode + session.getLoginData().getLoginname());
            }
        }
        catch (Exception e) {
            log.error("logout fail.", e);
            return new RestResponse<Integer>(1, "logout fail", 0);
        }
        return new RestResponse<Integer>(0, "OK", 0);
    }

    /* (non-Javadoc)
     * @see com.lenovo.lmrp.api.appgateway.IAppSoftware#getLastVersion(java.lang.String)
     */
    public RestResponse<AppVO> getLastVersion(String appName) {
        // TODO Auto-generated method stub
        return null;
    }

    /* (non-Javadoc)
     * @see com.lenovo.lmrp.api.appgateway.IAppSoftware#feedback(java.lang.String, com.lenovo.lmrp.api.model.view.FeedbackVO)
     */
    public RestResponse<AppVO> feedback(String appName, FeedbackVO feedback) {
        // TODO Auto-generated method stub
        return null;
    }

    /* (non-Javadoc)
     * @see com.lenovo.lmrp.api.appgateway.IAppSoftware#refresh(java.lang.String, java.lang.String)
     */
    public RestResponse<TokenVO> refresh(String itsmcode, Map<String, String> retoken) {
    	
        if (Objects.isNull(retoken) || CommonUtil.isNullOrEmpty(retoken.get("refreshtoken"))) {
            return new RestResponse<TokenVO>(1, "missing refreshtoken", null);
        }
        String refreshtoken = retoken.get("refreshtoken");
        CacheItem<AppSession> cacheSession = AppCache.getClient().get(AppSession.class,refreshtoken);
        //判断是否有效
        if (Objects.isNull(cacheSession) || Objects.isNull(cacheSession.getValue())) {
            return new RestResponse<TokenVO>(1, "invalid refreshtoken", null);
        }
        TokenVO tokenVO = null;
        AppSession session = cacheSession.getValue();
        if (!session.tokenExpired()) {//未过期
            tokenVO = new TokenVO(session.getToken(), refreshtoken, session.getExpireTime());
        }
        else {//已过期  重新创建token
        	ACacheClient client = AppCache.getClient();
        	client.remove(session.getToken());
        	client.remove(refreshtoken);
        	client.remove(itsmcode + session.getLoginData().getLoginname());
            tokenVO = this.createToken(itsmcode, session.getLoginData());
        }
        return new RestResponse<TokenVO>(0, "OK", tokenVO);

    }

    //创建session并缓存
    private TokenVO createToken(String itsmcode, LoginData loginData) {

        TokenGenerator generator = new TokenGenerator();
        AppSession session = new AppSession();
        //计算token到期时间  需要回传给APP
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.SECOND, PropertiesUtil.getAttributeBean().getAttribute("token.expiretime", 1800));

        session.setExpireTime(calendar.getTime());
        session.setLoginData(loginData);

        String token = generator.accessToken();
        String refreshToken = generator.refreshToken();

        session.setRefreshToken(refreshToken);
        session.setToken(token);
        //缓存session
        int cacheMaxttl = PropertiesUtil.getAttributeBean().getAttribute("appgateway.cache.maxttl", -1);
        CacheItem<AppSession> tokenItem = new CacheItem<AppSession>(token, session,null,cacheMaxttl);
        CacheItem<AppSession> retokenItem = new CacheItem<AppSession>(refreshToken, session,null,cacheMaxttl);
        CacheItem<AppSession> userItem = new CacheItem<AppSession>(itsmcode + loginData.getLoginname(), session,null,cacheMaxttl);
        //保存登录用户信息
        AppCache.getClient().put(tokenItem);
        AppCache.getClient().put(retokenItem);
        //用于检查重复登录
        AppCache.getClient().put(userItem);

        TokenVO tokenVO = new TokenVO(token, refreshToken, session.getExpireTime());
        return tokenVO;
    }

    //检查用户是否在其他设备登录
    private void logoutRepeat(String itsmcode, LoginData loginData) {

        CacheItem<AppSession> cacheSession = AppCache.getClient().get(AppSession.class,itsmcode + loginData.getLoginname());

        if (!Objects.isNull(cacheSession) && !Objects.isNull(cacheSession.getValue())) {
            //当前在线工程师的cid
            AppSession session = cacheSession.getValue();
            String onlineCid = session.getLoginData().getCid();
            if (!onlineCid.equals(loginData.getCid())) {
                //发送MQ消息，通知APP执行强制登出
                LoginData logoutCid = new LoginData();
                logoutCid.setCid(onlineCid);
                logoutCid.setDeviceid(session.getLoginData().getDeviceid());
                logoutCid.setLoginname(loginData.getLoginname());
                sendMQ(MQAppGatewayEvent.FORCELOGOUT, logoutCid, itsmcode);
                //清除session
                AppCache.getClient().remove(session.getToken());
                AppCache.getClient().remove(session.getRefreshToken());
                AppCache.getClient().remove(itsmcode + session.getLoginData().getLoginname());
            }
        }
    }

    //发送MQ消息
    private void sendMQ(MQAppGatewayEvent event, LoginData loginData, String itsmcode) {
        AMQClient mqClient = AppMQClient.getMQClient();
        MQContent mqContent = new MQContent();
        mqContent.setSource(MQTopic.APPGWEVENT.getSource());
        mqContent.setEvent(event.getEvent());
        mqContent.setItsmcode(itsmcode);
        mqContent.setContent(loginData);
        String msg;
        try {
            msg = JSONHelper.toJSON(mqContent);
            mqClient.publish(MQTopic.APPGWEVENT.name(), msg);
        }
        catch (Exception e) {
            log.error("force logout fail.", e);
        }
    }
}
